package it.traveldreamWeb.employee;

import it.traveldream.beans.ExcursionManagerInterface;
import it.traveldream.beans.HotelManagerInterface;
import it.traveldream.beans.PackageManagerInterface;
import it.traveldream.beans.TransportMeanManagerInterface;
import it.traveldream.dto.ExcursionDTO;
import it.traveldream.dto.HotelDTO;
import it.traveldream.dto.HotelDTO.HotelRoomType;
import it.traveldream.dto.LocationDTO;
import it.traveldream.dto.ProductDTO;
import it.traveldream.dto.TPDTO;
import it.traveldream.dto.TransportMeanDTO;
import it.traveldream.exceptions.InvalidProductException;
import it.traveldream.exceptions.LocationNotFoundException;
import it.traveldreamWeb.shared.ApplicationDataBean;
import it.traveldreamWeb.shared.HotelRoom;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

@ManagedBean(name="eHomeBean")
@ViewScoped
public class HomeBean {	
	
	private TransportMeanDTO insertedMean;
	private HotelDTO insertedHotel;
	private ExcursionDTO insertedExcursion;
	private List<HotelRoom> insertedRooms;
	
	private LocationDTO TPLocation;
	private List<TPDTO> availableTPs;
	private TPDTO selectedTP;
	private LocationDTO productLocation;
	private List<ProductDTO> availableProducts;
	private ProductDTO selectedProduct;
	
	private String error;
	
	@EJB
	private TransportMeanManagerInterface meanMgr;
	@EJB
	private HotelManagerInterface hotelMgr;
	@EJB
	private ExcursionManagerInterface excMgr;
	@EJB
	private PackageManagerInterface tpManager;
	
	@ManagedProperty(value="#{applicationDataBean}")
	private ApplicationDataBean appData;
	
	@ManagedProperty(value="#{eSessionBean}")
	private EmployeeSessionBean session;
	
	@PostConstruct
	private void init(){
		this.insertedMean = new TransportMeanDTO();
		this.insertedHotel = new HotelDTO();
		this.insertedExcursion = new ExcursionDTO();
		this.insertedRooms = new ArrayList<>();
		
		for (HotelRoomType type : this.appData.getRoomTypes()){
			HotelRoom r = new HotelRoom();
			r.setType(type);
			r.setPrice(new BigDecimal(0));
			r.setSelectedRooms(0);
			r.setTotalRooms(0);
			this.insertedRooms.add(r);
		}
		
		if (this.session.getSuccessMessage() != null){
			this.setError(this.session.getSuccessMessage());
			this.session.setSuccessMessage("");
		}
	}
	
	public void searchProducts(){
		if (this.productLocation == null){
			FacesMessage msg = new FacesMessage("Validation failed.", 
                    "Select one location");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage("productForm:productLocation", msg);
            return;
		}
		
		try {
			this.availableProducts = this.meanMgr.getProductsByLocation(this.productLocation);
		} catch (LocationNotFoundException e) {
			FacesMessage msg = new FacesMessage("Error.", 
                    "Invalid request. Bad location?");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage("productForm:productLocation", msg);
		}
	}
	
	public String modifyProduct(){
		this.setError("");
		try {
			if (this.selectedProduct == null)
				return null;
			
			String params = "pid=" + this.selectedProduct.getProductId() + 
					"&tid=" + this.selectedProduct.getProductType().getProductTypeId();
			return "ModifyProduct?faces-redirect=true&" + params;
		} catch (Exception e) {
			this.setError("Internal error! Pleare try again");
			return "";
		}
	}

	
	public String createTP(){
		this.setError("");
		if (this.TPLocation == null){
			FacesMessage msg = new FacesMessage("Validation failed.", 
                    "Select one location");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage("tpForm:TPLocation", msg);
            return null;
		}
		
		return "PackageCreation?faces-redirect=true&lid=" + this.TPLocation.getLocationId();
	}
	
	public void searchTP(){
		this.setError("");
		if (this.TPLocation == null){
			FacesMessage msg = new FacesMessage("Validation failed.", 
                    "Select one location");
            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage("tpForm:TPLocation", msg);
            return;
		}
		
		try {
			this.availableTPs = this.tpManager.getTPsByLocation(this.TPLocation);
		} catch (LocationNotFoundException e) {
			this.setError("Invalid request. Bad location?");
			return;
		} catch (Exception e) {
			this.setError("Internal error. Please try again.");
			return;
		}
	}
	
	public String modifyTP(){
		this.setError("");
		try {
			if (this.selectedTP == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Select one location");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("tpForm:TPLocation", msg);
	            return null;
			}
			
			String params = "tpid=" + this.selectedTP.getTPId();
			return "PackageCreation?faces-redirect=true&" + params;
		} catch (Exception e) {
			this.setError("Internal error! Pleare try again");
			return "";
		}
	}
	
	public void deleteTP(){
		this.setError("");
		try {
			if (this.selectedTP == null){
				this.setError("Please, select a travel package first");
				return;
			}
			
			this.tpManager.deleteTP(this.selectedTP);
			this.selectedTP = null;
			this.availableTPs = this.tpManager.getTPsByLocation(this.TPLocation);
			
			this.setError("Travel package deleted!");
		} catch (LocationNotFoundException e) {
			this.setError("Invalid request. Bad location?");
			return;
		} catch (Exception e) {
			this.setError("Internal error. Please try again.");
			return;
		}
	}
	
	public void saveMean(){
		this.setError("");
		try {
			if (this.insertedMean.getLocation() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Select one location");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("meanForm:destinationChoice", msg);
	            return;
			}
			if (this.insertedMean.getDeparture() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Select one departure");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("meanForm:departureChoice", msg);
	            return;
			}
			if (this.insertedMean.getSpaces() == 0){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Enter spaces");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("meanForm:spaceSelection", msg);
	            return;
			}
			
			this.meanMgr.saveProduct(this.insertedMean);
			this.insertedMean = new TransportMeanDTO();
			this.setError("Transport mean created!");
		} catch (InvalidProductException e) {
			this.setError("Internal error. Please try again");
		}
	}
	
	public void saveHotel(){
		this.setError("");
		try {
			if (this.insertedHotel.getLocation() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Select one location");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("hotelForm:locationHChoice", msg);
	            return;
			}
			Map<HotelRoomType, Integer> rooms = new HashMap<>();
			Map<HotelRoomType, BigDecimal> prices = new HashMap<>();
			for (HotelRoom r : this.insertedRooms){
				if (r.getTotalRooms() <= 0){
					FacesMessage msg = new FacesMessage("Validation failed.", 
		                    "Enter valid number");
		            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
		            FacesContext.getCurrentInstance().addMessage("hotelForm:rooms", msg);
					return;
				}
				if (r.getPrice().signum() != 1){
					FacesMessage msg = new FacesMessage("Validation failed.", 
		                    "Enter valid price");
		            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
		            FacesContext.getCurrentInstance().addMessage("hotelForm:rooms", msg);
					return;
				}
				rooms.put(r.getType(), r.getTotalRooms());
				prices.put(r.getType(), r.getPrice());
			}
			this.insertedHotel.setRooms(rooms);
			this.insertedHotel.setPrices(prices);
			this.hotelMgr.saveProduct(this.insertedHotel);
			this.insertedHotel = new HotelDTO();
			this.insertedRooms = new ArrayList<>();
			for (HotelRoomType type : this.appData.getRoomTypes()){
				HotelRoom r = new HotelRoom();
				r.setType(type);
				r.setPrice(new BigDecimal(0));
				r.setSelectedRooms(0);
				r.setTotalRooms(0);
				this.insertedRooms.add(r);
			}
			this.setError("Hotel created!");
		} catch (InvalidProductException e) {
			this.setError("Internal error. Please try again");
		}
	}
	
	public void saveExcursion(){
		this.setError("");
		try {
			if (this.insertedExcursion.getLocation() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
	                    "Select one location");
	            msg.setSeverity(FacesMessage.SEVERITY_ERROR);
	            FacesContext.getCurrentInstance().addMessage("meanForm:locationEChoice", msg);
	            return;
			}
			
			this.excMgr.saveProduct(this.insertedExcursion);
			this.insertedExcursion = new ExcursionDTO();
			this.setError("Excursion created!");
		} catch (InvalidProductException e) {
			this.setError("Internal error. Please try again");
		}
	}

	public ApplicationDataBean getAppData() {
		return this.appData;
	}

	public void setAppData(ApplicationDataBean appData) {
		this.appData = appData;
	}

	public TransportMeanDTO getInsertedMean() {
		return this.insertedMean;
	}
	public void setInsertedMean(TransportMeanDTO insertedMean) {
		this.insertedMean = insertedMean;
	}
	public HotelDTO getInsertedHotel() {
		return this.insertedHotel;
	}
	public void setInsertedHotel(HotelDTO insertedHotel) {
		this.insertedHotel = insertedHotel;
	}
	public ExcursionDTO getInsertedExcursion() {
		return this.insertedExcursion;
	}
	public void setInsertedExcursion(ExcursionDTO insertedExcursion) {
		this.insertedExcursion = insertedExcursion;
	}
	
	public List<HotelRoom> getInsertedRooms() {
		return this.insertedRooms;
	}

	public void setInsertedRooms(List<HotelRoom> insertedRooms) {
		this.insertedRooms = insertedRooms;
	}

	public LocationDTO getTPLocation() {
		return this.TPLocation;
	}

	public void setTPLocation(LocationDTO tPLocation) {
		this.TPLocation = tPLocation;
	}

	public String getError() {
		return this.error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public void setSession(EmployeeSessionBean session) {
		this.session = session;
	}

	public List<TPDTO> getAvailableTPs() {
		return this.availableTPs;
	}

	public void setAvailableTPs(List<TPDTO> availableTPs) {
		this.availableTPs = availableTPs;
	}

	public TPDTO getSelectedTP() {
		return this.selectedTP;
	}

	public void setSelectedTP(TPDTO tp) {
		this.selectedTP = tp;
	}

	public LocationDTO getProductLocation() {
		return this.productLocation;
	}

	public void setProductLocation(LocationDTO productLocation) {
		this.productLocation = productLocation;
	}

	public List<ProductDTO> getAvailableProducts() {
		return this.availableProducts;
	}

	public void setAvailableProducts(List<ProductDTO> availableProducts) {
		this.availableProducts = availableProducts;
	}

	public ProductDTO getSelectedProduct() {
		return this.selectedProduct;
	}

	public void setSelectedProduct(ProductDTO selectedProduct) {
		this.selectedProduct = selectedProduct;
	}
}
